/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * GraphicalUI.java
 *
 * Created on 02-Feb-2013, 14:42:20
 */
package simulator;

import java.util.List;
import java.io.File;
import javax.swing.JOptionPane;
import model.HighScore;
import pcomponents.PlantComponent;
import pcomponents.Condenser;
import pcomponents.Pump;
import pcomponents.Reactor;
import pcomponents.Turbine;
import pcomponents.Valve;

import java.awt.*;
import javax.swing.*;
/**
 *
 * @author bjw523
 */
public class GraphicalUI extends javax.swing.JFrame {

    private static final int    MAX_NAME_CHARACTERS = 17;
    private static final String ACTION_QUIT_GAME = "Performing this action will quit the current game, losing all unsaved progress.\nAre you sure you wish to continue?";
    private static final String ACTION_OVERWRITE = "Performing this action will overwrite the current savefile.\nAre you sure you wish to continue?";
    private static final String ENTER_NAME_MESSAGE = "Please enter your name.\n(Maximum " + MAX_NAME_CHARACTERS + " characters)";
    private static final String ENTER_NAME = "<Enter name here>";
    private static final String ENTER_STEP_TIMES = "Please enter number of times to Step.\n(Between 1 and 10)";
    private static final String NO_HIGHSCORES = "There are no highscores yet.\nPlay a game to be the first!\n";
    private static final String PLEASE_SELECT = "Please select one of the following options: ";
    private static final String ENTER_RPM = "Please enter the Rpm.\n(Between 0 and 1000)";
    private static final String ENTER_RODLEVEL = "Please enter the Rod Level.\n(Between 0 and 100)";
    private static final String AWT_DESKTOP = "Unfortunately, Awt Desktop is not available on this computer\nmeaning that you'll be unable to open this file.\nOur user manual can be seen on our website if you need any further help.";
    private static final String NO_TUTORIAL = "File not found, please see our user manual on our website instead.";
    private static final String COMMANDS = "To advance the system, use the turn buttons.\nEach turn button will advance the game by the amount stated\n\n"
            + "All information about the component the mouse is currently over\nwill be displayed on the right of the screen.\n\n\n"
            + "Components can be interacted with in multiple ways:\n\n"
            + "Left Click:\nIf the component has two states, this will toggle between them.\n"
            + "Scrolling:\nIf the component has a variable value, this will increment or\ndecrement it based on which direction you scroll.\n"
            + "Right Click:\nWill bring up a popup menu for that component allowing it to\nbe toggled, set or repaired easily.";
    private PlantController controller;
    private boolean popup = false;
    private String overComponent = null;
    private boolean debugMode = false; // if true, we're in godmode
    
    /**
     * Creates new form GraphicalUI
     * @param controller 
     */
    public GraphicalUI(PlantController controller) {
        this(controller, false);
    }
    
    /**
     * 
     * @param controller
     * @param debug
     */
    public GraphicalUI(PlantController controller, boolean debug) {
        debugMode = debug;
        getContentPane().setBackground(Color.white);
        this.controller = controller;
        initComponents();
        if (!newGame()) {
            System.exit(0);
        }
    }
    
    

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        jPopupMenu = new javax.swing.JPopupMenu();
        jMenuItemToggle = new javax.swing.JMenuItem();
        jMenuItemSet = new javax.swing.JMenuItem();
        jMenuItemRepair = new javax.swing.JMenuItem();
        jPanelTransContainer = new javax.swing.JPanel();
        jPanelValve2 = new javax.swing.JPanel();
        valve2image = new javax.swing.JLabel();
        jPanelCondenser = new javax.swing.JPanel();
        jLabelScore = new javax.swing.JLabel();
        jLabelName = new javax.swing.JLabel();
        jPanelPump2 = new javax.swing.JPanel();
        pump2Image = new javax.swing.JLabel();
        jPanelPump1 = new javax.swing.JPanel();
        pump1Image = new javax.swing.JLabel();
        jPanelPump3 = new javax.swing.JPanel();
        pump3Image = new javax.swing.JLabel();
        jLabel1 = new javax.swing.JLabel();
        jPanelValve1 = new javax.swing.JPanel();
        valve1image = new javax.swing.JLabel();
        jPanelReactor = new javax.swing.JPanel();
        jButtonStepN = new javax.swing.JButton();
        jButtonStep = new javax.swing.JButton();
        jPanelTurbine = new javax.swing.JPanel();
        jButtonStepTen = new javax.swing.JButton();
        jLabelTurbineFailed = new javax.swing.JLabel();
        jLabelPump1Failed = new javax.swing.JLabel();
        jLabelPump2Failed = new javax.swing.JLabel();
        jLabelPump3Failed = new javax.swing.JLabel();
        jLabelRods = new javax.swing.JLabel();
        jLabelWarningLight = new javax.swing.JLabel();
        jLabel2 = new javax.swing.JLabel();
        jLabelBackgroundImage = new javax.swing.JLabel();
        jMenuBar = new javax.swing.JMenuBar();
        jMenuFile = new javax.swing.JMenu();
        jMenuItemNew = new javax.swing.JMenuItem();
        jMenuItemSave = new javax.swing.JMenuItem();
        jMenuItemLoad = new javax.swing.JMenuItem();
        jMenuItemQuit = new javax.swing.JMenuItem();
        jMenuHelp = new javax.swing.JMenu();
        jMenuItemCommands = new javax.swing.JMenuItem();
        jMenuItemTutorial = new javax.swing.JMenuItem();

        jPopupMenu.addPopupMenuListener(new javax.swing.event.PopupMenuListener() {
            public void popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {
                jPopupMenuPopupMenuWillBecomeVisible(evt);
            }
            public void popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent evt) {
                jPopupMenuPopupMenuWillBecomeInvisible(evt);
            }
            public void popupMenuCanceled(javax.swing.event.PopupMenuEvent evt) {
            }
        });

        jMenuItemToggle.setText("jMenuItem1");
        jMenuItemToggle.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                jMenuItemToggleMouseReleased(evt);
            }
        });
        jPopupMenu.add(jMenuItemToggle);

        jMenuItemSet.setText("jMenuItem2");
        jMenuItemSet.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                jMenuItemSetMouseReleased(evt);
            }
        });
        jPopupMenu.add(jMenuItemSet);

        jMenuItemRepair.setText("jMenuItem3");
        jMenuItemRepair.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                jMenuItemRepairMouseReleased(evt);
            }
        });
        jPopupMenu.add(jMenuItemRepair);

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setResizable(false);
        getContentPane().setLayout(new java.awt.GridBagLayout());

        jPanelTransContainer.setName(""); // NOI18N
        jPanelTransContainer.setOpaque(false);
        jPanelTransContainer.setPreferredSize(new java.awt.Dimension(1024, 768));
        jPanelTransContainer.setLayout(null);

        jPanelValve2.setName("Valve2"); // NOI18N
        jPanelValve2.setOpaque(false);
        jPanelValve2.setPreferredSize(new java.awt.Dimension(48, 48));
        jPanelValve2.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jPanelMouseClicked(evt);
            }
            public void mouseEntered(java.awt.event.MouseEvent evt) {
                jPanelMouseEntered(evt);
            }
            public void mouseExited(java.awt.event.MouseEvent evt) {
                jPanelMouseExited(evt);
            }
        });
        jPanelValve2.setLayout(new java.awt.GridBagLayout());

        valve2image.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/valveopen.png"))); // NOI18N
        valve2image.setText("0");
        valve2image.setFocusable(false);
        jPanelValve2.add(valve2image, new java.awt.GridBagConstraints());

        jPanelTransContainer.add(jPanelValve2);
        jPanelValve2.setBounds(440, 184, 48, 48);

        jPanelCondenser.setName("Condenser"); // NOI18N
        jPanelCondenser.setOpaque(false);
        jPanelCondenser.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jPanelMouseClicked(evt);
            }
            public void mouseEntered(java.awt.event.MouseEvent evt) {
                jPanelMouseEntered(evt);
            }
            public void mouseExited(java.awt.event.MouseEvent evt) {
                jPanelMouseExited(evt);
            }
        });

        javax.swing.GroupLayout jPanelCondenserLayout = new javax.swing.GroupLayout(jPanelCondenser);
        jPanelCondenser.setLayout(jPanelCondenserLayout);
        jPanelCondenserLayout.setHorizontalGroup(
            jPanelCondenserLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 230, Short.MAX_VALUE)
        );
        jPanelCondenserLayout.setVerticalGroup(
            jPanelCondenserLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 280, Short.MAX_VALUE)
        );

        jPanelTransContainer.add(jPanelCondenser);
        jPanelCondenser.setBounds(420, 236, 230, 280);

        jLabelScore.setText("Score: 0");
        jPanelTransContainer.add(jLabelScore);
        jLabelScore.setBounds(50, 650, 230, 15);

        jLabelName.setText("<Insert Name>'s Powerplant");
        jPanelTransContainer.add(jLabelName);
        jLabelName.setBounds(50, 610, 240, 15);

        jPanelPump2.setMinimumSize(new java.awt.Dimension(48, 48));
        jPanelPump2.setName("Pump2"); // NOI18N
        jPanelPump2.setOpaque(false);
        jPanelPump2.setPreferredSize(new java.awt.Dimension(48, 48));
        jPanelPump2.addMouseWheelListener(new java.awt.event.MouseWheelListener() {
            public void mouseWheelMoved(java.awt.event.MouseWheelEvent evt) {
                jPanelMouseWheelMoved(evt);
            }
        });
        jPanelPump2.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jPanelMouseClicked(evt);
            }
            public void mouseEntered(java.awt.event.MouseEvent evt) {
                jPanelMouseEntered(evt);
            }
            public void mouseExited(java.awt.event.MouseEvent evt) {
                jPanelMouseExited(evt);
            }
        });
        jPanelPump2.setLayout(new java.awt.GridBagLayout());

        pump2Image.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/pumpoff.png"))); // NOI18N
        pump2Image.setFocusable(false);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        jPanelPump2.add(pump2Image, gridBagConstraints);

        jPanelTransContainer.add(jPanelPump2);
        jPanelPump2.setBounds(290, 410, 48, 48);

        jPanelPump1.setName("Pump1"); // NOI18N
        jPanelPump1.setOpaque(false);
        jPanelPump1.setPreferredSize(new java.awt.Dimension(48, 48));
        jPanelPump1.addMouseWheelListener(new java.awt.event.MouseWheelListener() {
            public void mouseWheelMoved(java.awt.event.MouseWheelEvent evt) {
                jPanelMouseWheelMoved(evt);
            }
        });
        jPanelPump1.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jPanelMouseClicked(evt);
            }
            public void mouseEntered(java.awt.event.MouseEvent evt) {
                jPanelMouseEntered(evt);
            }
            public void mouseExited(java.awt.event.MouseEvent evt) {
                jPanelMouseExited(evt);
            }
        });
        jPanelPump1.setLayout(new java.awt.GridBagLayout());

        pump1Image.setBackground(new java.awt.Color(204, 204, 204));
        pump1Image.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/pumpoff.png"))); // NOI18N
        pump1Image.setFocusable(false);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        jPanelPump1.add(pump1Image, gridBagConstraints);

        jPanelTransContainer.add(jPanelPump1);
        jPanelPump1.setBounds(290, 470, 48, 48);

        jPanelPump3.setMinimumSize(new java.awt.Dimension(48, 48));
        jPanelPump3.setName("Pump3"); // NOI18N
        jPanelPump3.setOpaque(false);
        jPanelPump3.setPreferredSize(new java.awt.Dimension(48, 48));
        jPanelPump3.addMouseWheelListener(new java.awt.event.MouseWheelListener() {
            public void mouseWheelMoved(java.awt.event.MouseWheelEvent evt) {
                jPanelMouseWheelMoved(evt);
            }
        });
        jPanelPump3.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jPanelMouseClicked(evt);
            }
            public void mouseEntered(java.awt.event.MouseEvent evt) {
                jPanelMouseEntered(evt);
            }
            public void mouseExited(java.awt.event.MouseEvent evt) {
                jPanelMouseExited(evt);
            }
        });
        jPanelPump3.setLayout(new java.awt.GridBagLayout());

        pump3Image.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/pumpoff.png"))); // NOI18N
        pump3Image.setFocusable(false);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        jPanelPump3.add(pump3Image, gridBagConstraints);

        jPanelTransContainer.add(jPanelPump3);
        jPanelPump3.setBounds(670, 440, 48, 48);

        jLabel1.setText("jLabel1");
        jPanelTransContainer.add(jLabel1);
        jLabel1.setBounds(770, 60, 210, 330);

        jPanelValve1.setName("Valve1"); // NOI18N
        jPanelValve1.setOpaque(false);
        jPanelValve1.setPreferredSize(new java.awt.Dimension(48, 48));
        jPanelValve1.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jPanelMouseClicked(evt);
            }
            public void mouseEntered(java.awt.event.MouseEvent evt) {
                jPanelMouseEntered(evt);
            }
            public void mouseExited(java.awt.event.MouseEvent evt) {
                jPanelMouseExited(evt);
            }
        });
        jPanelValve1.setLayout(new java.awt.GridBagLayout());

        valve1image.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/valveopenrotated.png"))); // NOI18N
        valve1image.setFocusable(false);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        jPanelValve1.add(valve1image, gridBagConstraints);

        jPanelTransContainer.add(jPanelValve1);
        jPanelValve1.setBounds(197, 150, 48, 48);

        jPanelReactor.setInheritsPopupMenu(true);
        jPanelReactor.setName("Reactor"); // NOI18N
        jPanelReactor.setOpaque(false);
        jPanelReactor.addMouseWheelListener(new java.awt.event.MouseWheelListener() {
            public void mouseWheelMoved(java.awt.event.MouseWheelEvent evt) {
                jPanelMouseWheelMoved(evt);
            }
        });
        jPanelReactor.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jPanelMouseClicked(evt);
            }
            public void mouseEntered(java.awt.event.MouseEvent evt) {
                jPanelMouseEntered(evt);
            }
            public void mouseExited(java.awt.event.MouseEvent evt) {
                jPanelMouseExited(evt);
            }
        });

        javax.swing.GroupLayout jPanelReactorLayout = new javax.swing.GroupLayout(jPanelReactor);
        jPanelReactor.setLayout(jPanelReactorLayout);
        jPanelReactorLayout.setHorizontalGroup(
            jPanelReactorLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 160, Short.MAX_VALUE)
        );
        jPanelReactorLayout.setVerticalGroup(
            jPanelReactorLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 250, Short.MAX_VALUE)
        );

        jPanelTransContainer.add(jPanelReactor);
        jPanelReactor.setBounds(50, 269, 160, 250);

        jButtonStepN.setText("Turn (n)");
        jButtonStepN.setMaximumSize(new java.awt.Dimension(90, 23));
        jButtonStepN.setMinimumSize(new java.awt.Dimension(90, 23));
        jButtonStepN.setPreferredSize(new java.awt.Dimension(90, 23));
        jButtonStepN.setVerticalAlignment(javax.swing.SwingConstants.TOP);
        jButtonStepN.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jButtonStepNMouseClicked(evt);
            }
        });
        jPanelTransContainer.add(jButtonStepN);
        jButtonStepN.setBounds(700, 670, 140, 23);

        jButtonStep.setText("Turn (1)");
        jButtonStep.setMaximumSize(new java.awt.Dimension(90, 23));
        jButtonStep.setMinimumSize(new java.awt.Dimension(90, 23));
        jButtonStep.setPreferredSize(new java.awt.Dimension(90, 23));
        jButtonStep.setRequestFocusEnabled(false);
        jButtonStep.setVerticalAlignment(javax.swing.SwingConstants.TOP);
        jButtonStep.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jButtonStepMouseClicked(evt);
            }
        });
        jButtonStep.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonStepActionPerformed(evt);
            }
        });
        jPanelTransContainer.add(jButtonStep);
        jButtonStep.setBounds(700, 590, 140, 23);

        jPanelTurbine.setName("Turbine"); // NOI18N
        jPanelTurbine.setOpaque(false);
        jPanelTurbine.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jPanelMouseClicked(evt);
            }
            public void mouseEntered(java.awt.event.MouseEvent evt) {
                jPanelMouseEntered(evt);
            }
            public void mouseExited(java.awt.event.MouseEvent evt) {
                jPanelMouseExited(evt);
            }
        });

        javax.swing.GroupLayout jPanelTurbineLayout = new javax.swing.GroupLayout(jPanelTurbine);
        jPanelTurbine.setLayout(jPanelTurbineLayout);
        jPanelTurbineLayout.setHorizontalGroup(
            jPanelTurbineLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 170, Short.MAX_VALUE)
        );
        jPanelTurbineLayout.setVerticalGroup(
            jPanelTurbineLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 140, Short.MAX_VALUE)
        );

        jPanelTransContainer.add(jPanelTurbine);
        jPanelTurbine.setBounds(270, 60, 170, 140);

        jButtonStepTen.setText("Turn (10)");
        jButtonStepTen.setMaximumSize(new java.awt.Dimension(90, 23));
        jButtonStepTen.setMinimumSize(new java.awt.Dimension(90, 23));
        jButtonStepTen.setPreferredSize(new java.awt.Dimension(90, 23));
        jButtonStepTen.setVerticalAlignment(javax.swing.SwingConstants.TOP);
        jButtonStepTen.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jButtonStepTenMouseClicked(evt);
            }
        });
        jPanelTransContainer.add(jButtonStepTen);
        jButtonStepTen.setBounds(700, 630, 140, 23);

        jLabelTurbineFailed.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/turbinefailed.png"))); // NOI18N
        jLabelTurbineFailed.setEnabled(false);
        jLabelTurbineFailed.setFocusable(false);
        jPanelTransContainer.add(jLabelTurbineFailed);
        jLabelTurbineFailed.setBounds(270, 60, 170, 140);

        jLabelPump1Failed.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/pumpfailed.png"))); // NOI18N
        jLabelPump1Failed.setEnabled(false);
        jLabelPump1Failed.setFocusable(false);
        jPanelTransContainer.add(jLabelPump1Failed);
        jLabelPump1Failed.setBounds(290, 470, 50, 50);

        jLabelPump2Failed.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/pumpfailed.png"))); // NOI18N
        jLabelPump2Failed.setEnabled(false);
        jLabelPump2Failed.setFocusable(false);
        jPanelTransContainer.add(jLabelPump2Failed);
        jLabelPump2Failed.setBounds(290, 410, 50, 50);

        jLabelPump3Failed.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/pumpfailed.png"))); // NOI18N
        jLabelPump3Failed.setEnabled(false);
        jLabelPump3Failed.setFocusable(false);
        jPanelTransContainer.add(jLabelPump3Failed);
        jLabelPump3Failed.setBounds(670, 440, 50, 50);

        jLabelRods.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/rods.png"))); // NOI18N
        jLabelRods.setFocusable(false);
        jPanelTransContainer.add(jLabelRods);
        jLabelRods.setBounds(75, 389, 110, 130);

        jLabelWarningLight.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/warninglightoff.png"))); // NOI18N
        jLabelWarningLight.setFocusable(false);
        jPanelTransContainer.add(jLabelWarningLight);
        jLabelWarningLight.setBounds(670, 60, 50, 50);

        jLabel2.setText("Software Fault");
        jPanelTransContainer.add(jLabel2);
        jLabel2.setBounds(560, 70, 130, 30);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        getContentPane().add(jPanelTransContainer, gridBagConstraints);

        jLabelBackgroundImage.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/background.png"))); // NOI18N
        jLabelBackgroundImage.setFocusable(false);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        getContentPane().add(jLabelBackgroundImage, gridBagConstraints);

        jMenuFile.setText("File");

        jMenuItemNew.setText("New");
        jMenuItemNew.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItemNewActionPerformed(evt);
            }
        });
        jMenuFile.add(jMenuItemNew);

        jMenuItemSave.setText("Save");
        jMenuItemSave.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItemSaveActionPerformed(evt);
            }
        });
        jMenuFile.add(jMenuItemSave);

        jMenuItemLoad.setText("Load");
        jMenuItemLoad.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItemLoadActionPerformed(evt);
            }
        });
        jMenuFile.add(jMenuItemLoad);

        jMenuItemQuit.setText("Quit");
        jMenuItemQuit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItemQuitActionPerformed(evt);
            }
        });
        jMenuFile.add(jMenuItemQuit);

        jMenuBar.add(jMenuFile);

        jMenuHelp.setText("Help");

        jMenuItemCommands.setText("Commands");
        jMenuItemCommands.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItemCommandsActionPerformed(evt);
            }
        });
        jMenuHelp.add(jMenuItemCommands);

        jMenuItemTutorial.setText("Tutorial");
        jMenuItemTutorial.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItemTutorialActionPerformed(evt);
            }
        });
        jMenuHelp.add(jMenuItemTutorial);

        jMenuBar.add(jMenuHelp);

        setJMenuBar(jMenuBar);

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void jMenuItemNewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemNewActionPerformed
        if (confirmQuitDialog()) {
            newGame();
        }
    }//GEN-LAST:event_jMenuItemNewActionPerformed

    private void jMenuItemSaveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemSaveActionPerformed
        if (confirmOverwriteDialog()) {
            saveGame();
        }
    }//GEN-LAST:event_jMenuItemSaveActionPerformed

    private void jMenuItemLoadActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemLoadActionPerformed
        if (confirmQuitDialog()) {
            loadGame();
        }
    }//GEN-LAST:event_jMenuItemLoadActionPerformed

    private void jMenuItemQuitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemQuitActionPerformed
        if (confirmQuitDialog()) {
            gameOver();
        }
    }//GEN-LAST:event_jMenuItemQuitActionPerformed

    private void jButtonStepMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jButtonStepMouseClicked
        if (((javax.swing.JButton)(evt.getSource())).isEnabled()) {
            doStep(1);
        }
    }//GEN-LAST:event_jButtonStepMouseClicked

    private void jButtonStepTenMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jButtonStepTenMouseClicked
        if (((javax.swing.JButton)(evt.getSource())).isEnabled()) {
            doStep(10);
        }
    }//GEN-LAST:event_jButtonStepTenMouseClicked

    private void jButtonStepNMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jButtonStepNMouseClicked
        if (((javax.swing.JButton)(evt.getSource())).isEnabled()) {
            int stepN = stepNDialog();
            if (stepN != -1) {
                doStep(stepN);
            }
        }
    }//GEN-LAST:event_jButtonStepNMouseClicked

    private void jPanelMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jPanelMouseClicked
        if (controller.getPlant().getOperatorSoftware().isOperational()) {
            if (evt.getButton() == java.awt.event.MouseEvent.BUTTON1) {
                handleLeftClick(((javax.swing.JPanel) (evt.getSource())).getName());
            } else if (evt.getButton() == java.awt.event.MouseEvent.BUTTON3) {
                //TODO Refactor
                setPopupMenu(((javax.swing.JPanel) (evt.getSource())).getName());
                if (!((javax.swing.JPanel) (evt.getSource())).getName().equals("Condenser")) {
                    jPopupMenu.setName(((javax.swing.JPanel) (evt.getSource())).getName());
                    jMenuItemToggle.setName(((javax.swing.JPanel) (evt.getSource())).getName());
                    jMenuItemSet.setName(((javax.swing.JPanel) (evt.getSource())).getName());
                    jMenuItemRepair.setName(((javax.swing.JPanel) (evt.getSource())).getName());
                    jPopupMenu.show(evt.getComponent(), evt.getX(), evt.getY());
                }
            }
        }
    }//GEN-LAST:event_jPanelMouseClicked

    private void jPanelMouseEntered(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jPanelMouseEntered
        if (!popup) {
            updateInterface(((javax.swing.JPanel)(evt.getSource())).getName());
        }
        overComponent = ((javax.swing.JPanel)(evt.getSource())).getName();
    }//GEN-LAST:event_jPanelMouseEntered

    private void jPanelMouseExited(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jPanelMouseExited
        if (!popup) {
            updateInterface(null);
        }
        overComponent = null;
    }//GEN-LAST:event_jPanelMouseExited

    private void jPanelMouseWheelMoved(java.awt.event.MouseWheelEvent evt) {//GEN-FIRST:event_jPanelMouseWheelMoved
        if (controller.getPlant().getOperatorSoftware().isOperational()) {
            handleMouseWheel(((javax.swing.JPanel)(evt.getSource())).getName(), evt.getWheelRotation());
        }
    }//GEN-LAST:event_jPanelMouseWheelMoved

    private void jPopupMenuPopupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent evt) {//GEN-FIRST:event_jPopupMenuPopupMenuWillBecomeInvisible
        popup = false;
        if (overComponent != null) {
            if (overComponent.equals(((javax.swing.JPopupMenu) (evt.getSource())).getName())) {
                updateInterface(((javax.swing.JPopupMenu) (evt.getSource())).getName());
            }
        } else {
            updateInterface(null);
        }
    }//GEN-LAST:event_jPopupMenuPopupMenuWillBecomeInvisible

    private void jPopupMenuPopupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {//GEN-FIRST:event_jPopupMenuPopupMenuWillBecomeVisible
        popup = true;
        updateInterface(((javax.swing.JPopupMenu)(evt.getSource())).getName());
    }//GEN-LAST:event_jPopupMenuPopupMenuWillBecomeVisible

    private void jMenuItemToggleMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jMenuItemToggleMouseReleased
        handleLeftClick(((JMenuItem)(evt.getSource())).getName());
        popup = false;
        updateInterface(((javax.swing.JMenuItem)(evt.getSource())).getName());
    }//GEN-LAST:event_jMenuItemToggleMouseReleased

    private void jMenuItemSetMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jMenuItemSetMouseReleased
        handleSet(((javax.swing.JMenuItem)(evt.getSource())).getName());
        popup = false;
        updateInterface(((javax.swing.JMenuItem)(evt.getSource())).getName());
    }//GEN-LAST:event_jMenuItemSetMouseReleased

    private void jMenuItemRepairMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jMenuItemRepairMouseReleased
        handleRepair(((javax.swing.JMenuItem)(evt.getSource())).getName());
        popup = false;
        updateInterface(((javax.swing.JMenuItem) (evt.getSource())).getName());
    }//GEN-LAST:event_jMenuItemRepairMouseReleased

    private void jButtonStepActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonStepActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_jButtonStepActionPerformed

    private void jMenuItemTutorialActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemTutorialActionPerformed
        if (Desktop.isDesktopSupported()) {
            try {
                File file = new File("/resources/UserManual.pdf");
                Desktop.getDesktop().open(file);
            } catch (Exception ex) {
                showFailureDialog(NO_TUTORIAL, "Uh oh!");
            }
        } else {
            showFailureDialog(AWT_DESKTOP, "Uh oh!");
        }
    }//GEN-LAST:event_jMenuItemTutorialActionPerformed

    private void jMenuItemCommandsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemCommandsActionPerformed
        showCommands();
    }//GEN-LAST:event_jMenuItemCommandsActionPerformed

    /*
     * -------------------------------------------------------------------------
     * Interface Functions
     */
    
    /**
     * Displays all of the commands available to the user.
     */
    private void showCommands() {
        JOptionPane.showMessageDialog(null, COMMANDS, "Commands", JOptionPane.PLAIN_MESSAGE);
    }
    /**
     * Resets the interface to show the new operator name, reset the score and
     * values of components.
     */
    private void resetInterface() {
        jLabelName.setText(controller.getUIData().getOperatorName() + "'s Powerplant");
        updateJLabelScore();
        updateInterface(null);
        setComponentsEnabled(true);
        jLabelTurbineFailed.setEnabled(false);
        jLabelPump1Failed.setEnabled(false);
        jLabelPump2Failed.setEnabled(false);
        jLabelPump3Failed.setEnabled(false);
    }

    /**
     * Updates the values shown to represent the name of the component given.
     * If passed a null string, the values will all be set to n/a.
     * <p>
     * Works by calling multiple functions and concatenating the returned strings
     * all ending in line breaks and then displaying this multiple lined string.
     * 
     * Also updates the dynamic images in the UI based on the current data in UIData
     * 
     * @param name the component being shown
     */
    private void updateInterface(String name) {
        String str = "<html>";
        if (name == null) {
            str += "<br>";
        } else {
            str += name + "<br>";
        }
        str += updateHealth(name);
        str += updateStatus(name);
        str += updateState(name);
        str += updateVariable(name);
        str += updateTemp(name);
        str += updatePressure(name);
        str += updateWaterVol(name);
        str += updateSteamVol(name);
        str += "</html>";
        jLabel1.setText(str);

        //<editor-fold desc="Failures">
        if (controller.getUIData().isTurbineFunctional()) {
            jLabelTurbineFailed.setEnabled(false);
        } else {
            jLabelTurbineFailed.setEnabled(true);
        }

        if (controller.getUIData().getPumps().get(0).isOperational()) {
            jLabelPump1Failed.setEnabled(false);
        } else {
            jLabelPump1Failed.setEnabled(true);
        }

        if (controller.getUIData().getPumps().get(1).isOperational()) {
            jLabelPump2Failed.setEnabled(false);
        } else {
            jLabelPump2Failed.setEnabled(true);
        }

        if (controller.getUIData().getPumps().get(2).isOperational()) {
            jLabelPump3Failed.setEnabled(false);
        } else {
            jLabelPump3Failed.setEnabled(true);
        }
        //</editor-fold>

        //<editor-fold desc="Valves">
        if (controller.getUIData().getValves().get(0).isOpen()) {
            valve1image.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/valveopenrotated.png")));
        } else {
            valve1image.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/valveclosedrotated.png")));
        }

        if (controller.getUIData().getValves().get(1).isOpen()) {
            valve2image.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/valveopen.png")));
        } else {
            valve2image.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/valveclosed.png")));
        }
        //</editor-fold>

        //<editor-fold desc="Pumps">
        if ((controller.getUIData().getPumps().get(0).getRpm() + 249) / 250 > 0){
            pump1Image.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/pumpon.gif")));
        } else {
            pump1Image.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/pumpoff.png")));
        }

        if ((controller.getUIData().getPumps().get(1).getRpm() + 249) / 250 > 0){
            pump2Image.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/pumpon.gif")));
        } else {
            pump2Image.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/pumpoff.png")));
        }
        
        if ((controller.getUIData().getPumps().get(2).getRpm() + 249) / 250 > 0){
            pump3Image.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/pumpon.gif")));
        } else {
            pump3Image.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/pumpoff.png")));
        }
        //</editor-fold>
        
        //<editor-fold desc="Rods">       
        jLabelRods.setBounds(75, (304 + (controller.getUIData().getControlRodsPercentage())), 112, 103);
        //</editor-fold>
        
        //<editor-fold desc="WarningLight">
        if (controller.getUIData().getOperatorSoftwareOperational()) {
            jLabelWarningLight.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/warninglightoff.png")));
        } else {
            jLabelWarningLight.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/warninglighton.png")));
        }
        //</editor-fold>
    }
    
    /**
     * If the component is a Reactor or Condenser, the health is shown, otherwise
     * the value is set to n/a.
     * 
     * @param name the component being shown
     * @return a formalised String representing the value
     */
    private String updateHealth(String name) {
        Object pc = getComponent(name);
        String str = "Health: ";
        if (pc instanceof Reactor) {
            Reactor reactor = (Reactor)(pc);
            str += reactor.getHealth();
        } else if (pc instanceof Condenser) {
            Condenser condenser = (Condenser)(pc);
            str += condenser.getHealth();            
        } else {
            str += "n/a";
        }
        return str += "<br>";
    }
    
    /**
     * If the component is a Turbine or a Pump, the status is shown, otherwise
     * the value is set to n/a.
     * 
     * @param name the component being shown
     * @return a formalised String representing the value
     */
    private String updateStatus(String name) {
        Object pc = getComponent(name);
        String str = "Status: ";
        if (pc instanceof Turbine) {
            Turbine turbine = (Turbine)(pc);
            str += flagToStatus(turbine.isOperational());
        } else if (pc instanceof Pump) {
            Pump pump = (Pump)(pc);
            str += flagToStatus(pump.isOperational());
        } else {
            str += "n/a";
        }
        return str += "<br>";
    }
    
    /**
     * If the component is a Pump or a Valve, the state is shown, otherwise
     * the value is set to n/a.
     * 
     * @param name the component being shown
     * @return a formalised String representing the value
     */
    private String updateState(String name) {
        Object pc = getComponent(name);
        String str = "State: ";
        if (pc instanceof Pump) {
            Pump pump = (Pump)(pc);
            str += flagToState(pump.isOn());
        } else if (pc instanceof Valve) {
            Valve valve = (Valve)(pc);
            str += flagToState(valve.isOpen());
        } else {
            str += "n/a";
        }
        return str += "<br>";
    }
    
    /**
     * If the component is a Reactor, Turbine or a Pump, the Rodlevel or Rpm is 
     * shown (Rodlevel for the Reactor, Rpm for the Turbine or Pumps), otherwise 
     * the value is set to n/a.
     * 
     * @param name the component being shown
     * @return a formalised String representing the value
     */
    private String updateVariable(String name) {
        Object pc = getComponent(name);
        String str = "";
        if (pc instanceof Reactor) {
            Reactor reactor = (Reactor)(pc);
            str += "Rodlevel: " + reactor.getPercentageLowered();
        } else if (pc instanceof Pump) {
            Pump pump = (Pump)(pc);
            str += "Rpm: " + pump.getRpm();
        } else if (pc instanceof Turbine) {
            Turbine turbine = (Turbine)(pc);
            str += "Rpm: " + turbine.getRpm();
        } else {
            str += "Component Specific Info: n/a";
        }
        return str += "<br>";
    }
    
    /**
     * If the component is a Reactor or a Condenser, the temperature is shown, 
     * otherwise the value is set to n/a.
     * 
     * @param name the component being shown
     * @return a formalised String representing the value
     */
    private String updateTemp(String name) {
        Object pc = getComponent(name);
        String str = "Temperature: ";
        if (pc instanceof Reactor) {
            Reactor reactor = (Reactor) (pc);
            str += reactor.getTemperature();
        } else if (pc instanceof Condenser) {
            Condenser condenser = (Condenser) (pc);
            str += condenser.getTemperature();
        } else {
            str += "n/a";
        }
        return str += "<br>";
    }
    
    /**
     * If the component is a Reactor or a Condenser, the Pressure is shown, 
     * otherwise the value is set to n/a.
     * 
     * @param name the component being shown
     * @return a formalised String representing the value
     */
    private String updatePressure(String name) {
        Object pc = getComponent(name);
        String str = "Pressure: ";
        if (pc instanceof Reactor) {
            Reactor reactor = (Reactor) (pc);
            str += reactor.getPressure();
        } else if (pc instanceof Condenser) {
            Condenser condenser = (Condenser) (pc);
            str += condenser.getPressure();
        } else {
            str += "n/a";
        }
        return str += "<br>";
    }
    
    /**
     * If the component is a Reactor or a Condenser, the Water Volume is shown, 
     * otherwise the value is set to n/a.
     * 
     * @param name the component being shown
     * @return a formalised String representing the value
     */
    private String updateWaterVol(String name) {
        Object pc = getComponent(name);
        String str = "WaterVolume: ";
        if (pc instanceof Reactor) {
            Reactor reactor = (Reactor) (pc);
            str += reactor.getWaterVolume();
        } else if (pc instanceof Condenser) {
            Condenser condenser = (Condenser) (pc);
            str += condenser.getWaterVolume();
        } else {
            str += "n/a";
        }
        return str += "<br>";
    }
    
    /**
     * If the component is a Reactor or a Condenser, the Steam Volume is shown, 
     * otherwise the value is set to n/a.
     * 
     * @param name the component being shown
     * @return a formalised String representing the value
     */
    private String updateSteamVol(String name) {
        Object pc = getComponent(name);
        String str = "SteamVolume: ";
        if (pc instanceof Reactor) {
            Reactor reactor = (Reactor) (pc);
            str += reactor.getSteamVolume();
        } else if (pc instanceof Condenser) {
            Condenser condenser = (Condenser) (pc);
            str += condenser.getSteamVolume();
        } else {
            str += "n/a";
        }
        return str += "<br>";
    }
    
    /**
     * Converts a true/false value into "Operational"/"Inoperable".
     * 
     * @param b status
     * @return an English version of the boolean value
     */
    private String flagToStatus(boolean b) {
        if (b) {
            return "Operational";
        } else {
            return "Inoperable";
        }
    }
    
    /**
     * Converts a true/false value into "On"/"Off".
     * 
     * @param b state
     * @return an English version of the boolean value
     */
    private String flagToState(boolean b) {
        if (b) {
            return "On";
        } else {
            return "Off";
        }
    }
    
    /**
     * Updates the JLabelScore text to show the current score. 
     */
    private void updateJLabelScore() {
        jLabelScore.setText("Score: " + controller.getPlant().getScore());
    }
    
    /**
     * Displays a dialog indicating a Successful operation.
     * 
     * @param message the main text body of the dialog
     * @param title the title to be shown
     */
    private void showSuccessDialog(String message, String title) {
        JOptionPane.showMessageDialog(null, message, title, JOptionPane.INFORMATION_MESSAGE);
    }
    
    /**
     * Displays a dialog indicating a Failed operation.
     * 
     * @param message the main text body of the dialog
     * @param title the title to be shown
     */
    private void showFailureDialog(String message, String title) {
        JOptionPane.showMessageDialog(null, message, title, JOptionPane.ERROR_MESSAGE);
    }
    
    /**
     * Shows a dialog asking for an input and then returns that input if it's 
     * an integer between 1 and 10 (inclusive). Returns -1 if the dialog is
     * cancelled.
     *
     * @return number of steps to take
     */
    public int stepNDialog() {
        int stepN = -1;
        while(stepN < 1 || stepN > 10) {
            String input = JOptionPane.showInputDialog(ENTER_STEP_TIMES);
            if (input == null) { // user pressed cancel
                return -1;
            }
            stepN = tryParse(input);
        }
        return stepN;
    }

    /**
     * Converts a string into an integer, or returns -1 if it's not a valid integer.
     * 
     * @param s the string to parse
     * @return the parsed integer
     */
    private int tryParse(String s) {
        try {
            return Integer.parseInt(s);
        } catch (NumberFormatException e) {
            return -1;
        }
    }
    
    /**
     * Shows a dialog confirming whether the user wishes to quit the current
     * game or not, the options given are yes and no.
     *
     * @return a boolean indicating whether yes or no was pressed
     */
    private boolean confirmQuitDialog() {
        int input = javax.swing.JOptionPane.showConfirmDialog(null, ACTION_QUIT_GAME, "Attention!",
                javax.swing.JOptionPane.YES_NO_OPTION, javax.swing.JOptionPane.WARNING_MESSAGE);
        if (input == javax.swing.JOptionPane.YES_OPTION) {
            return true;
        } else {
            return false;
        }
    }
    
    /**
     * Shows a dialog confirming whether the user wishes to overwrite the current
     * saved game or not, the options given are yes and no.
     * 
     * @return a boolean indicating whether yes or no was pressed
     */
    private boolean confirmOverwriteDialog() {
        int input = javax.swing.JOptionPane.showConfirmDialog(null, ACTION_OVERWRITE, "Attention!",
                javax.swing.JOptionPane.YES_NO_OPTION, javax.swing.JOptionPane.WARNING_MESSAGE);
        if (input == javax.swing.JOptionPane.YES_OPTION) {
            return true;
        } else {
            return false;
        }
    }
    
    /**
     * Asks the user it input their name. The dialog will persist until a valid
     * name is entered or cancel is pressed. If cancel is pressed, null will be
     * returned.
     * 
     * @return the name inputted by the user
     */
    private String newGameDialog() {
        String input = "", defaultName;
        if (controller.getUIData().getOperatorName() == null) {
            defaultName = ENTER_NAME;
        } else {
            // in case we already have an operator name
            defaultName = controller.getUIData().getOperatorName(); 
        }
        while (input.length() > MAX_NAME_CHARACTERS || input.equals("") || input.equals(ENTER_NAME)) {
            input = javax.swing.JOptionPane.showInputDialog(ENTER_NAME_MESSAGE, defaultName);
            if (input == null) {
                return null;
            }
        }
        return input;
    }
    
    /**
     * Displays a dialog showing the current highscores and gives the options to
     * start a new game, load a game or exit. The function returns 0, 1 and 2
     * respectively.
     * 
     * @param highScores a list of HighScores
     * @return an integer representing the option selected
     */
    private int highScoreDialog(List<HighScore> highScores) {
        Object[] options = {"New Game", "Load Game", "Exit"};
        return javax.swing.JOptionPane.showOptionDialog(null, getHighScoreDisplay(highScores)+ PLEASE_SELECT,
                "Game Over", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE,
                null, options, options[0]);
    }
    
    /**
     * Takes each HighScore from the list of HighScores, appends it to the number
     * it is in the list, and adds a newline at the end. Each HighScore has a name
     * component and a score component. If no HighScores are given, then a
     * specific message is shown instead.
     * 
     * @param highScores a list of HighScores
     * @return a String containing all of the highscores to be displayed
     */
    private String getHighScoreDisplay(List<HighScore> highScores) {
        String highScoreDisplay = "Highscores:\n";
            if (!highScores.isEmpty()) {
                int i = 1;
                for (HighScore h : highScores) {
                    highScoreDisplay += i + ". " + h.getName() + ": " + h.getHighScore() + "\n";
                    i++;
                }
            } else {
                highScoreDisplay += NO_HIGHSCORES;
            }
            highScoreDisplay += "\n";
            return highScoreDisplay;
    }

    /**
     * Handles a left click command on a given component. If the component is a 
     * Pump or a Valve, the component has had it's state changed.
     * 
     * @param input the name of the component to be handled
     */
    public void handleLeftClick(String input) {
        Object pComponent = getComponent(input);
        if (pComponent instanceof Pump) {
            Pump pump = (Pump)(pComponent);
            setPumpOnOff(pump.getID(), pump.isOn());         
        } else if (pComponent instanceof Valve) {
            Valve valve = (Valve)(pComponent);
            setValve(valve.getID(), valve.isOpen());
        }     
        controller.getUIData().updateUIData();
        updateInterface(input);
    }
    
    /**
     * Updates the Reactors rodlevel or a Pumps rpm depending on how much the 
     * mouse wheel has been moved.
     * 
     * @param input the component to be handled
     * @param change the amount that the mouse wheel has moved
     */
    public void handleMouseWheel(String input, int change) {
        Object pComponent = getComponent(input);
        if (pComponent instanceof Reactor) {
            setControlRods(controller.getUIData().getControlRodsPercentage() - change);
        } else if (pComponent instanceof Pump) {
            Pump pump = (Pump)(pComponent);
            if (pump.isOn()) {
                setPumpRpm(pump.getID(), pump.getRpm() - (10 * change));
            }
        }
        controller.getUIData().updateUIData();
        updateInterface(input);
    }
    
    /**
     * Sets either the Reactor or a Pump depending on the value returned from 
     * the relevant dialog.
     * 
     * @param input the component to be handled
     */
    public void handleSet(String input) {
        Object pComponent = getComponent(input);
        int value;
        if (pComponent instanceof Reactor) {
            value = setRodlevelDialog();
            if (value != -1) {
                setControlRods(value);
            }
        } else if (pComponent instanceof Pump) {
            value = setRpmDialog();
            if (value != -1) {
                Pump pump = (Pump) (pComponent);
                setPumpRpm(pump.getID(), value);
            }
        }
    }
    
    /**
     * Shows a dialog, asking the user to input a valid rpm to set a pump to.
     * The value is only accepted if it is between 0 and 1000 (inclusive).
     * 
     * @return the Rpm inputted
     */
    private int setRpmDialog() {
        int rpm = -1;
        while (rpm < 0 || rpm > 1000) {
            String input = JOptionPane.showInputDialog(ENTER_RPM);
            if (input == null) { // user pressed cancel
                return -1;
            }
            rpm = tryParse(input);
        }
        return rpm;
    }
    
    /**
     * Shows a dialog, asking the user to input a valid rod level to set the 
     * Reactor to. The value is only accepted if it is between 0 and 100
     * (inclusive).
     * @return the rod level inputted
     */
    private int setRodlevelDialog() {
        int Rodlevel = -1;
        while (Rodlevel < 0 || Rodlevel > 100) {
            String input = JOptionPane.showInputDialog(ENTER_RODLEVEL);
            if (input == null) { // user pressed cancel
                return -1;
            }
            Rodlevel = tryParse(input);
        }
        return Rodlevel;
    }
    
    /**
     * If the given component is a Turbine or a Pump, the program tries to 
     * repair it.
     * 
     * @param input the component to be handled
     */
    public void handleRepair(String input) {
        Object pComponent = getComponent(input);
        if (pComponent instanceof Turbine) {
            repairTurbine();
        } else if (pComponent instanceof Pump) {
            Pump pump = (Pump)(pComponent);
            repairPump(pump.getID());
        }
    }
    
    /**
     * Sets the relevant menu items to display in the popup menu based on which
     * component has been passed to the function.
     * 
     * @param input the component that has been clicked
     */
    private void setPopupMenu(String input) {
        Object pComponent = getComponent(input);
        if (pComponent instanceof Reactor) {
            jMenuItemToggle.hide();
            jMenuItemSet.setText("Set Rod Level");
            jMenuItemSet.show();
            jMenuItemRepair.hide();
        } else if (pComponent instanceof Condenser) {
            jMenuItemToggle.hide();
            jMenuItemSet.hide();
            jMenuItemRepair.hide();
        } else if (pComponent instanceof Turbine) {
            jMenuItemToggle.hide();
            jMenuItemSet.hide();
            jMenuItemRepair.setText("Repair");
            jMenuItemRepair.show();
        } else if (pComponent instanceof Pump) {
            jMenuItemToggle.setText("Turn " + flagToState(!((Pump)(pComponent)).isOn()));
            jMenuItemToggle.show();
            jMenuItemSet.setText("Set Rpm");
            jMenuItemSet.show();
            jMenuItemRepair.setText("Repair");
            jMenuItemRepair.show();
        } else if (pComponent instanceof Valve) {
            jMenuItemToggle.setText("Turn " + flagToState(!((Valve)(pComponent)).isOpen()));
            jMenuItemToggle.show();
            jMenuItemSet.hide();
            jMenuItemRepair.hide();
        }
    }
    
    /**
     * Takes the name of a component and returns the physical component that it
     * corresponds to.
     * 
     * @param input the name of the component
     * @return an actual component of the plant
     */
    private PlantComponent getComponent(String input) {
        if (input == null) {
            return null;
        }
        model.Plant plant = controller.getPlant();
        String substring = input.substring(0, 4);
        if (substring.equals("Reac")) {
            return plant.getReactor();
        } else if (substring.equals("Cond")) {
            return plant.getCondenser();
        } else if (substring.equals("Turb")) {
            return plant.getTurbine();
        } else if (substring.equals("Pump")) {
            int id = Integer.parseInt(input.substring(4));
            return plant.getPumps().get(id - 1);
        } else if (substring.equals("Valv")) {
            int id = Integer.parseInt(input.substring(5));
            return plant.getValves().get(id - 1);
        }
        return null;
    }
    /*
     * -------------------------------------------------------------------------
     * Game Functions
     */
    
    /**
     * Shows the newGameDialog and then returns false if the dialog was cancelled, 
     * otherwise creates a new game and resets the interface, finally returning
     * true to indicate that the new game has been initialised.
     * 
     * @return a value detailing whether a new game has been accepted or not
     */
    private boolean newGame() {
        
        String name = debugMode ? "Galactus" : newGameDialog();
        if (name == null) {
            return false;
        } else {
            controller.newGame(name);
            resetInterface();
            //TODO Remove me once components are implemented.
            //controller.setControlRods(10);
            return true;
        }
    }

    /**
     * Attempts to save the game, and then displays to the user whether the game
     * was successfully saved or not. Relevant messages and titles are given for
     * each distinct case.
     */
    private void saveGame() {
        //TODO create constant strings
        if (!controller.getUIData().isGameOver()) {
            if (controller.saveGame()) {
                showSuccessDialog("Game successfully saved.", "Success!");
            } else {
                showFailureDialog("Could not save game.", "Error.");
            } 
            
        } else {
            showFailureDialog("Game already has finished. Can not save.", "Sorry.");
        }
    }

    /**
     * Attempts to load a game. Displays a relevant message and title for whether 
     * the game is loaded or not.
     */
    private void loadGame() {
        //TODO create constant strings
        if (controller.loadGame()) {
            showSuccessDialog("Game successfully loaded.", "Success!");
            resetInterface();
        } else {
            showFailureDialog("Could not open save file (no file present).", "Uh oh!");
        }
                
    }

    /**
     * Gets the high scores from the controller, shows a dialog and depending on
     * which option is chosen, either a new game is started, a game is loaded or
     * the game is exited.
     */
    private void gameOver() {
        setComponentsEnabled(false);
        List<HighScore> highScores = controller.getHighScores();
        
        do {
            int input = highScoreDialog(highScores);
            switch (input) {
                case 0:
                    newGame();
                    break;
                case 1:
                    loadGame();
                    break;
                case 2:
                    System.exit(0);
                    break;
            }
        } while (controller.getUIData().isGameOver());
    }
    
    /**
     * Sets all components to be enabled or disabled depending on the given 
     * boolean value.
     * 
     * @param b whether the components are to be set enabled or disabled
     */
    private void setComponentsEnabled(boolean b) {
        //TODO
        jLabelBackgroundImage.enable(b);
        for (java.awt.Component obj : jPanelTransContainer.getComponents()) {
            obj.enable(b);
            if (obj instanceof JPanel) {
                for (java.awt.Component panelObj : ((JPanel)(obj)).getComponents()) {
                    panelObj.enable(b);
                }
            }
        }
    }

    /**
     * Steps and updates the system. The system is stepped by the integer given.
     *
     * @param numSteps
     */
    public void doStep(int numSteps) {
        controller.step(numSteps);
        List<PlantComponent> brokenOnStep = controller.getUIData().getBrokenOnStep();
        for (PlantComponent pc : brokenOnStep) {
            if (pc instanceof Turbine) {
                //TODO code to execute for the turbine being broken
            } else if (pc instanceof Pump) {
                //TODO code to execute for a Pump being broken
            }
        }
        // TODO: check this resetBrokenOnStep()
        controller.getUIData().resetBrokenOnStep();
        controller.getUIData().updateUIData();
        updateJLabelScore();
        if (controller.getUIData().isGameOver()) {
            gameOver();
        }
        updateInterface(null);
    }

    /*
     * -------------------------------------------------------------------------
     * Component Functions
     */
    /**
     * Sets the valve specified by the id to be the opposite of what it's 
     * currently set to.
     *
     * @param valveID the id of the valve to be set
     * @param input the value of the valve currently
     */
    private void setValve(int valveID, boolean input) {
        controller.setValve(valveID, !input);
    }

    /**
     * Sets the pump specified by the id to be on or off depending on what it's
     * currently set to.
     *
     * @param pumpID the id of the pump to be set
     * @param input whether the pump is on or off currently
     */
    private void setPumpOnOff(int pumpID, boolean input) {
        controller.setPumpOnOff(pumpID, !input);
    }

    /**
     * Sets the pump specified by the id to be the rpm given.
     * 
     * @param pumpID the id of the pump to be set
     * @param input  the rpm to set the pump to
     */
    private void setPumpRpm(int pumpID, int input) {
        controller.setPumpRpm(pumpID, input);
    }

    /**
     * Sets the control rods of the Reactor to be the given integer.
     *
     * @param input the value to set the control rods to
     */
    private void setControlRods(int input) {
        controller.setControlRods(input);
    }

    /**
     * Repairs the turbine.
     */
    private void repairTurbine() {
        if (controller.repairTurbine()) {
            //TODO Dialog saying Turbine being repaied
        } else {
            //TODO dialog saying turbine is either functional or already being repaired
        } //Perhaps some other form of visual feedback..?
    }

    /**
     * Repairs the pump specified by the id given.
     *
     * @param ID the id of the pump to be repaired.
     */
    private void repairPump(int pumpID) {
                
        if (controller.repairPump(pumpID)) {
            //TODO Dialog saying Pump being repaied
        } else {
            //TODO dialog saying Pump is either functional or already being repaired
        } //Perhaps some other form of visual feedback..?
    }


    // Variables declaration - do not modify//GEN-BEGIN:variables
    public javax.swing.JButton jButtonStep;
    public javax.swing.JButton jButtonStepN;
    public javax.swing.JButton jButtonStepTen;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabelBackgroundImage;
    private javax.swing.JLabel jLabelName;
    private javax.swing.JLabel jLabelPump1Failed;
    private javax.swing.JLabel jLabelPump2Failed;
    private javax.swing.JLabel jLabelPump3Failed;
    private javax.swing.JLabel jLabelRods;
    private javax.swing.JLabel jLabelScore;
    private javax.swing.JLabel jLabelTurbineFailed;
    private javax.swing.JLabel jLabelWarningLight;
    public javax.swing.JMenuBar jMenuBar;
    private javax.swing.JMenu jMenuFile;
    private javax.swing.JMenu jMenuHelp;
    private javax.swing.JMenuItem jMenuItemCommands;
    private javax.swing.JMenuItem jMenuItemLoad;
    private javax.swing.JMenuItem jMenuItemNew;
    private javax.swing.JMenuItem jMenuItemQuit;
    private javax.swing.JMenuItem jMenuItemRepair;
    private javax.swing.JMenuItem jMenuItemSave;
    private javax.swing.JMenuItem jMenuItemSet;
    private javax.swing.JMenuItem jMenuItemToggle;
    private javax.swing.JMenuItem jMenuItemTutorial;
    public javax.swing.JPanel jPanelCondenser;
    private javax.swing.JPanel jPanelPump1;
    private javax.swing.JPanel jPanelPump2;
    private javax.swing.JPanel jPanelPump3;
    public javax.swing.JPanel jPanelReactor;
    private javax.swing.JPanel jPanelTransContainer;
    public javax.swing.JPanel jPanelTurbine;
    private javax.swing.JPanel jPanelValve1;
    private javax.swing.JPanel jPanelValve2;
    private javax.swing.JPopupMenu jPopupMenu;
    public javax.swing.JLabel pump1Image;
    public javax.swing.JLabel pump2Image;
    public javax.swing.JLabel pump3Image;
    public javax.swing.JLabel valve1image;
    public javax.swing.JLabel valve2image;
    // End of variables declaration//GEN-END:variables
}
